Skip to content

3.0 Project | Story App by Kuzmin M#14

Open
Raritetnik wants to merge 1 commit intodemologin:mainfrom
Raritetnik:kuzmin
Open

3.0 Project | Story App by Kuzmin M#14
Raritetnik wants to merge 1 commit intodemologin:mainfrom
Raritetnik:kuzmin

Conversation

@Raritetnik
Copy link

No description provided.

@Raritetnik Raritetnik changed the title 3.0 Project | Story App 3.0 Project | Story App by Kuzmin M Feb 12, 2026
Copy link
Owner

@demologin demologin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Общий вывод по проекту

Представленный код демонстрирует хорошее владение базовым синтаксисом Java и продвинутыми механизмами.

Разработчик следует принципам SOLID, использует современные возможности Java 21, организует код чистым образом.

Проект демонстрирует хорошее понимание объектно-ориентированного программирования и базовых принципов Java Web. Использование Optional, ConcurrentHashMap и неизменяемых коллекций говорит о зрелом подходе к написанию кода. Основные точки роста: внедрение полноценного логирования (вместо замалчивания ошибок), более строгое соблюдение SOLID (особенно интерфейсов репозитория) и избавление от "магических строк".

Рекомендации:

  • Продолжить углубление знаний по паттернам проектирования
  • Изучить асинхронное программирование более глубоко
  • Уделить внимание документированию кода

Итоговая оценка: B


public class InMemoryStoryRepository implements StoryRepository {

private final Map<String, Story> storage = new ConcurrentHashMap<>();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Инициализация хранилища напрямую нарушает гибкость. Следует рассмотреть возможность передачи Map через конструктор для облегчения тестирования. [INFO]


private final Map<String, Story> storage = new ConcurrentHashMap<>();

public void put(Story story) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод put отсутствует в интерфейсе StoryRepository. Это нарушает принцип подстановки Лисков (L). Компоненты, использующие интерфейс, не смогут добавить историю. [ERROR]

import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование 'import java.util.*;' считается плохой практикой (wildcard import). Следует импортировать только необходимые классы. [WARNING]

public class StoryLoader {

// Analyze story file
public Story load(String code, InputStream in) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод load слишком длинный и выполняет слишком много задач (парсинг, валидация, сборка). Рекомендуется разделить его на приватные методы согласно Single Responsibility Principle. [WARNING]


// Analyze story file
public Story load(String code, InputStream in) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отсутствует логирование процесса загрузки. Вместо стандартных исключений стоит добавить логирование уровня INFO или DEBUG для отслеживания загрузки файлов. [INFO]

nodeKey = paramNode == null || paramNode.isBlank() ? "START" : paramNode;

// Session Stats
HttpSession session = req.getSession(true);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Создание сессии 'req.getSession(true)' в каждом запросе может избыточно расходовать память. Для чтения достаточно false, если сессия не создана ранее. [INFO]

}

Story story = storyRepository.findByCode(storyCode)
.orElseThrow(() -> new IllegalArgumentException("Story not found: " + storyCode));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод findByCode возвращает Optional, но тут же выбрасывается исключение. Это правильно, но сообщение об ошибке стоит сделать более информативным для пользователя. [INFO]


public StoryNode getNode(String key) {
StoryNode node = nodes.get(key);
if (node == null) throw new IllegalArgumentException("Unknown node: " + key);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IllegalArgumentException здесь уместен, но это runtime-ошибка логики данных. Стоит проверить целостность истории на этапе загрузки в StoryLoader. [INFO]

// validate links
for (StoryNode n : nodes.values()) {
for (Choice c : n.getChoices()) {
if (!nodes.containsKey(c.getNextNodeKey())) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Циклическая проверка ссылок выполняется вложенными циклами (O(n*m)). Для больших файлов это может быть медленно, хотя для квеста допустимо. [INFO]


import java.io.Serializable;

public class GameSession implements Serializable {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отсутствует serialVersionUID в классе, реализующем Serializable. Это может привести к InvalidClassException при десериализации после изменения класса. [ERROR]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants